package com.swsc.solarverse.schedule;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.swsc.solarverse.common.config.ResParams;
import com.swsc.solarverse.common.enums.OrganTypeEnums;
import com.swsc.solarverse.common.enums.StateEnums;
import com.swsc.solarverse.common.util.CalculateUtils;
import com.swsc.solarverse.common.util.LocalDateTimeUtils;
import com.swsc.solarverse.dao.entity.analysis.CorporationEfficiencyRecordDO;
import com.swsc.solarverse.dao.entity.analysis.StringEfficiencyRecordDO;
import com.swsc.solarverse.dao.entity.forward.ForwardStringLeDiagnoseRecordDO;
import com.swsc.solarverse.dao.entity.sys.CorporationDO;
import com.swsc.solarverse.dao.mapper.CustomSqlMapper;
import com.swsc.solarverse.service.analysis.ICorporationEfficiencyRecordService;
import com.swsc.solarverse.service.analysis.IStringEfficiencyRecordService;
import com.swsc.solarverse.service.forward.IForwardDeviceInfoService;
import com.swsc.solarverse.service.forward.IForwardStringLeDiagnoseRecordService;
import com.swsc.solarverse.service.schedule.StringEfficiencyRecordAnalysisService;
import com.swsc.solarverse.service.sys.ICorporationService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author chencl
 * @Date 2024/6/4 11:55
 * @Version 1.0
 * @Description 组串能效/发电量计算
 */
@lombok.extern.slf4j.Slf4j
@org.springframework.stereotype.Component
public class StringEfficiencyRecordAnalysisScheduledTask {
    public static final int CPU_NUM = Runtime.getRuntime().availableProcessors();
    private final ICorporationService corporationService;
    private final IForwardStringLeDiagnoseRecordService forwardStringLeDiagnoseRecordService;
    private final IForwardDeviceInfoService forwardDeviceInfoService;
    private final IStringEfficiencyRecordService stringEfficiencyRecordService;
    private final ICorporationEfficiencyRecordService corporationEfficiencyRecordService;
    private final CustomSqlMapper customSqlMapper;
    private final StringEfficiencyRecordAnalysisService stringEfficiencyRecordAnalysisService;

    public StringEfficiencyRecordAnalysisScheduledTask(ICorporationService corporationService,
                                                       IForwardStringLeDiagnoseRecordService forwardStringLeDiagnoseRecordService,
                                                       IForwardDeviceInfoService forwardDeviceInfoService,
                                                       IStringEfficiencyRecordService stringEfficiencyRecordService,
                                                       ICorporationEfficiencyRecordService corporationEfficiencyRecordService,
                                                       CustomSqlMapper customSqlMapper,
                                                       StringEfficiencyRecordAnalysisService stringEfficiencyRecordAnalysisService) {
        this.corporationService = corporationService;
        this.forwardStringLeDiagnoseRecordService = forwardStringLeDiagnoseRecordService;
        this.forwardDeviceInfoService = forwardDeviceInfoService;
        this.stringEfficiencyRecordService = stringEfficiencyRecordService;
        this.corporationEfficiencyRecordService = corporationEfficiencyRecordService;
        this.customSqlMapper = customSqlMapper;
        this.stringEfficiencyRecordAnalysisService = stringEfficiencyRecordAnalysisService;
    }

    /**
     * 每天晚上23点开始计算
     * 修改取数为9~15点的数据, 每天18点执行
     */
    @org.springframework.scheduling.annotation.Scheduled(cron = "0 0 18 * * ?")
    public void analysisString() {
        if (!ResParams.analysisStrIuLossEEnable) {
            log.info("未开启低效组串发电量计算任务...");
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        log.info("低效组串发电量计算-开始...");
        List<CorporationDO> corporationDos = corporationService.list(Wrappers.lambdaQuery(CorporationDO.class)
                .eq(CorporationDO::getOrganType, OrganTypeEnums.PS.getType())
                .eq(CorporationDO::getState, StateEnums.ENABLE.getEnable()));
        if (CollectionUtils.isEmpty(corporationDos)) {
            log.info("低效组串发电量计算-未查询到电站组织信息...");
            return;
        }
        LocalDateTime dataTime = now.withHour(11).withMinute(10).withSecond(0).withNano(0);
        log.info("低效组串发电量计算-查询数据: {}", dataTime);
        for (CorporationDO corporationDo : corporationDos) {
            // 分析电站数据
//            analysisStationStringData(corporationDo, dataTime, now);
            // 新的计算方式2024-08-02 15:51
            stringEfficiencyRecordAnalysisService.analysisStationStringDataNew(corporationDo, dataTime, now);

        }
    }

    private List<ForwardStringLeDiagnoseRecordDO> listAllDiagnoseRecords(CorporationDO corporationDo, LocalDateTime diagnoseTime) {
        List<ForwardStringLeDiagnoseRecordDO> diagnoseRecordDos = forwardStringLeDiagnoseRecordService.list(Wrappers.lambdaQuery(ForwardStringLeDiagnoseRecordDO.class)
                .eq(ForwardStringLeDiagnoseRecordDO::getTenantNo, corporationDo.getTenantNo())
                .eq(ForwardStringLeDiagnoseRecordDO::getOrganNo, corporationDo.getOrganNo())
                .eq(ForwardStringLeDiagnoseRecordDO::getDiagnoseTime, diagnoseTime)
        );
        log.info("低效组串发电量计算-查询所有低效诊断数据: {}, {}, {}条", corporationDo.getOrganNo(), diagnoseTime, diagnoseRecordDos.size());
        if (CollectionUtils.isEmpty(diagnoseRecordDos)) {
            LocalDateTime newDiagnoseTime = diagnoseTime.minusMinutes(10);
            diagnoseRecordDos = forwardStringLeDiagnoseRecordService.list(Wrappers.lambdaQuery(ForwardStringLeDiagnoseRecordDO.class)
                    .eq(ForwardStringLeDiagnoseRecordDO::getTenantNo, corporationDo.getTenantNo())
                    .eq(ForwardStringLeDiagnoseRecordDO::getOrganNo, corporationDo.getOrganNo())
                    .eq(ForwardStringLeDiagnoseRecordDO::getDiagnoseTime, newDiagnoseTime)
            );
            log.info("低效组串发电量计算-查询所有低效诊断数据: {}, {}, {}条", corporationDo.getOrganNo(), newDiagnoseTime, diagnoseRecordDos.size());
        }
        return diagnoseRecordDos;
    }

    /**
     * 只保留最近三个月的数据
     */
    @org.springframework.scheduling.annotation.Scheduled(cron = "0 0 2 * * ?")
    public void deleteExpireRecord() {
        QueryWrapper<StringEfficiencyRecordDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("distinct organ_no, data_time").orderByDesc("data_time");
        List<StringEfficiencyRecordDO> efficiencyRecordDos = stringEfficiencyRecordService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(efficiencyRecordDos)) {
            Map<Integer, List<StringEfficiencyRecordDO>> distinctRecordMap = efficiencyRecordDos.stream().collect(Collectors.groupingBy(StringEfficiencyRecordDO::getOrganNo));
            for (Map.Entry<Integer, List<StringEfficiencyRecordDO>> entry : distinctRecordMap.entrySet()) {
                if (CollectionUtils.isNotEmpty(entry.getValue())) {
                    LocalDateTime dataTime = entry.getValue().get(0).getDataTime();
                    if (null != dataTime) {
                        dataTime = dataTime.minusDays(365);
                        boolean flag = stringEfficiencyRecordService.remove(Wrappers.lambdaQuery(StringEfficiencyRecordDO.class)
                                .eq(StringEfficiencyRecordDO::getOrganNo, entry.getKey())
                                .lt(StringEfficiencyRecordDO::getDataTime, dataTime)
                        );
                        log.info("删除[{}]90天前的低效组串电量数据: {}, {}", entry.getKey(), dataTime, flag);
                    }
                }
            }
        }
    }

//    @org.springframework.scheduling.annotation.Scheduled(cron = "0 30 2 * * ?")
    public void analysisCorporation() {
        LocalDateTime now = LocalDateTime.now();
        log.info("场站低效组串发电量计算-开始...");
        List<CorporationDO> corporationDos = corporationService.list(Wrappers.lambdaQuery(CorporationDO.class)
                .eq(CorporationDO::getOrganType, OrganTypeEnums.PS.getType())
                .eq(CorporationDO::getState, StateEnums.ENABLE.getEnable()));
        if (CollectionUtils.isEmpty(corporationDos)) {
            log.info("场站低效组串发电量计算-未查询到电站组织信息...");
            return;
        }

        for (CorporationDO corporationDo : corporationDos) {
            // 分析电站数据
            analysisCorporationData(corporationDo, now);
        }
    }

    private void analysisCorporationData(CorporationDO corporationDo, LocalDateTime now) {
        LocalDateTime corpMaxDataTime = corporationEfficiencyRecordService.maxDataTime(corporationDo.getOrganNo());
        log.info("[{}]场站低效组串发电量计算-场站数据最大时间: {}", corporationDo.getOrganNo(), corpMaxDataTime);
        LocalDateTime yesterdayStart = LocalDateTimeUtils.getDayStart(now).minusDays(1L);
        LocalDateTime dataTime = null;
        if (null == corpMaxDataTime) {
            LocalDateTime stringMinDataTime = stringEfficiencyRecordService.minDataTime(corporationDo.getOrganNo());
            if (null != stringMinDataTime) {
                dataTime = stringMinDataTime;
                while (dataTime.compareTo(yesterdayStart) <= 0) {
                    analysisCorporationData(corporationDo, dataTime, now);
                    dataTime = dataTime.plusDays(1L);
                }
            }
        } else {
            dataTime = corpMaxDataTime.plusDays(1L);
            if (dataTime.compareTo(yesterdayStart) <= 0) {
                analysisCorporationData(corporationDo, dataTime, now);
            }
        }
    }

    private void analysisCorporationData(CorporationDO corporationDo, LocalDateTime dataTime, LocalDateTime now) {
        if (null != corporationDo && null != dataTime) {
            log.info("[{}]场站低效组串发电量计算-分析数据时间: {}, {}", corporationDo.getOrganNo(), dataTime, now);
            List<StringEfficiencyRecordDO> efficiencyRecordDos = stringEfficiencyRecordService.list(Wrappers.lambdaQuery(StringEfficiencyRecordDO.class)
                    .eq(StringEfficiencyRecordDO::getTenantNo, corporationDo.getTenantNo())
                    .eq(StringEfficiencyRecordDO::getOrganNo, corporationDo.getOrganNo())
                    .eq(StringEfficiencyRecordDO::getDataTime, dataTime)
            );
            Map<String, Integer> submatrixStringCountMap = new HashMap<>(efficiencyRecordDos.size());
            Double totalEff = null;
            Double totalLossE = null;
            for (StringEfficiencyRecordDO efficiencyRecordDo : efficiencyRecordDos) {
                if (StringUtils.isNotBlank(efficiencyRecordDo.getSubmatrix()) && null != efficiencyRecordDo.getSubmatrixStringNum()) {
                    submatrixStringCountMap.put(efficiencyRecordDo.getSubmatrix(), efficiencyRecordDo.getSubmatrixStringNum());
                }
                totalEff = CalculateUtils.plus(totalEff, efficiencyRecordDo.getEfficiency());
                totalLossE = CalculateUtils.plus(totalLossE, efficiencyRecordDo.getLossE());
            }
            Integer stringNum = submatrixStringCountMap.values().stream().reduce(Integer::sum).orElse(0);
            Double avgLossE = (null == totalLossE ? null : totalLossE / efficiencyRecordDos.size());

            Double accAvgLossE = null;
            CorporationEfficiencyRecordDO lastRecord = corporationEfficiencyRecordService.getLatestRecord(corporationDo.getTenantNo(), corporationDo.getOrganNo());
            if (null != lastRecord) {
                accAvgLossE = lastRecord.getAccAvgLossE();
                accAvgLossE = CalculateUtils.plus(accAvgLossE, avgLossE);
            }
            CorporationEfficiencyRecordDO efficiencyRecordDo = new CorporationEfficiencyRecordDO(corporationDo.getTenantNo(),
                    corporationDo.getOrganNo(), dataTime, totalEff, stringNum, avgLossE, accAvgLossE, now);
            log.info("[{}]场站低效组串发电量计算-保存分析数据开始: {}, {}", corporationDo.getOrganNo(), dataTime, now);
            corporationEfficiencyRecordService.save(efficiencyRecordDo);
            log.info("[{}]场站低效组串发电量计算-保存分析数据完成: {}, {}", corporationDo.getOrganNo(), dataTime, now);
        }
    }



    /**
     * 每天凌晨3:30点开始计算
     * 前置任务, 组串能效计算
     * @see StringEfficiencyAnalysisScheduledTask#dailyAnalysis1
     * 修改取数为9~15点的数据, 每天18点执行
     */
//    @org.springframework.scheduling.annotation.Scheduled(cron = "0 30 3 * * ?")
    public void analysisStringRecord() {
        if (!ResParams.analysisStrIuLossEEnable) {
            log.info("未开启低效组串发电量统计任务...");
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        log.info("低效组串发电量统计-开始...");
        List<CorporationDO> corporationDos = corporationService.list(Wrappers.lambdaQuery(CorporationDO.class)
                .eq(CorporationDO::getOrganType, OrganTypeEnums.PS.getType())
                .eq(CorporationDO::getState, StateEnums.ENABLE.getEnable()));
        if (CollectionUtils.isEmpty(corporationDos)) {
            log.info("低效组串发电量统计-未查询到电站组织信息...");
            return;
        }
        LocalDateTime dataTime = now.withHour(11).withMinute(10).withSecond(0).withNano(0);
        log.info("低效组串发电量统计-查询数据: {}", dataTime);
        for (CorporationDO corporationDo : corporationDos) {
            // 分析电站数据
//            analysisStationStringData(corporationDo, dataTime, now);
            // 新的计算方式2024-08-02 15:51
//            stringEfficiencyRecordAnalysisService.analysisStationStringDataNew(corporationDo, dataTime, now);

        }
    }
}
